package com.zp.demo.repush.config;

import com.zp.demo.repush.RePushUtils;
import com.zp.demo.repush.event.RepayPlanEvent;
import com.zp.demo.repush.exception.RePushException;
import com.zp.demo.repush.service.defined.DefinedRePushFitter;
import com.zp.demo.repush.vo.BaseRePushVo;
import com.zp.demo.repush.vo.RePushStrategyEntity;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;


/**
 * 异常捕获拦截
 * @author zhangpeng
 * @since 2018/8/17
 */
@ControllerAdvice
@Log4j2
public class RePushExceptionControllerAdvice {
    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private DefinedRePushFitter rePushFitter;
    @Autowired
    private HttpServletRequest request;
    @Autowired
    Map<String,RePushStrategyEntity> exceptionStrategy;

    /**
     * 需要重新推送的异常捕获
     * 使用观察者模式，在listener里面做相应的处理
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = RePushException.class)
    public Object errorRePushExceptionHandler(RePushException ex) {
        BaseRePushVo rePushVo = ex.getRePushVo();
        // 过滤是否已经在重推队列中
        RePushStrategyEntity baseStrategy = this.getStrategyProperties(rePushVo.getStrategyKey());
        String key = RePushUtils.generKey(rePushVo);
        // 如果已经在重推中，就不要再推了
        boolean isFitter = rePushFitter.needRePush(key, baseStrategy.getSleepTime() * baseStrategy.getCounts());
        if (!isFitter) {
            Assert.notNull(rePushVo.getOldResult(), "未设置 原返回结果：oldResult 未传入值");
            log.info("过滤>>>>>>>>>------------出现异常，但是已经在重推了-------------");
            return rePushVo.getOldResult();
        }
        // 出现异常
        // 使用spring 事件进行监听
        RepayPlanEvent event = new RepayPlanEvent(applicationContext);
        event.setRePushVo(ex.getRePushVo());
        applicationContext.publishEvent(event);
        return rePushVo.getOldResult();

    }

    /**
     * 获取配置的策略
     * @param exceptionKey
     * @return
     */
    private RePushStrategyEntity getStrategyProperties(String exceptionKey) {
        // 获取重推策略
        RePushStrategyEntity baseStrategy = exceptionStrategy.get(exceptionKey);
        if(baseStrategy == null){
            baseStrategy = exceptionStrategy.get("master");
        }
        return baseStrategy;
    }
}
